bitkeeper revision 1.760 (40436d00pAWlfO-5kOcLlyUpl-Vl0Q)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Mon, 1 Mar 2004 17:04:00 +0000 (17:04 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Mon, 1 Mar 2004 17:04:00 +0000 (17:04 +0000)
event_channel.c, xend.c, Makefile, xc_domain.c, xc.h:
  Another point on the way to shared comms rings. The console concentrator is coming along.

tools/xc/lib/xc.h
tools/xc/lib/xc_domain.c
tools/xend/Makefile
tools/xend/xend.c
xen/common/event_channel.c

index 907aa56c302436e35ae04702d69e049cfd4e464a..2f2d26919ec35e4665e1e615fc45e5469b82c8b0 100644 (file)
@@ -28,6 +28,7 @@ typedef struct {
     int           has_cpu;
     int           stopped;
     unsigned long nr_pages;
+    unsigned long shared_info_frame;
     u64           cpu_time;
 #define XC_DOMINFO_MAXNAME 16
     char          name[XC_DOMINFO_MAXNAME];
index 759e3ecfc718a721524f31b50c0d331e05e7a57f..4d68f5d937809c823da54a3ee3a069fe52fc4e97 100644 (file)
@@ -91,6 +91,7 @@ int xc_domain_getinfo(int xc_handle,
         info->has_cpu = op.u.getdomaininfo.has_cpu;
         info->stopped = (op.u.getdomaininfo.state == DOMSTATE_STOPPED);
         info->nr_pages = op.u.getdomaininfo.tot_pages;
+        info->shared_info_frame = op.u.getdomaininfo.shared_info_frame;
         info->cpu_time = op.u.getdomaininfo.cpu_time;
         strncpy(info->name, op.u.getdomaininfo.name, XC_DOMINFO_MAXNAME);
         info->name[XC_DOMINFO_MAXNAME-1] = '\0';
index 1fb84e0aaf5c3d9c278a78998a9a671cd6f07dce..ab31f8c6284d2d925e6c3160fe9b4612ea793714 100644 (file)
@@ -1,7 +1,7 @@
 
 CC       = gcc
 CFLAGS   = -Wall -O3 
-CFLAGS  += -I../../xen/include -I../../xenolinux-sparse/include
+CFLAGS  += -I../xc/lib
 
 HDRS     = $(wildcard *.h)
 OBJS     = $(patsubst %.c,%.o,$(wildcard *.c))
@@ -24,7 +24,7 @@ clean:
        $(RM) *.a *.so *.o *.rpm $(BIN)
 
 $(BIN): $(OBJS)
-       $(CC) $(CFLAGS) -o $@ $^ -L../xc/lib -lxc
+       $(CC) -o $@ $^ -L../xc/lib -lxc
 
 %.o: %.c $(HDRS) Makefile
        $(CC) $(CFLAGS) -c -o $@ $<
index 9da656e0a1440d5d49128d9b9abb1e0d7c39f8dd..208db8da0d1ca096f83482d3cfd4f5f53f319ad3 100644 (file)
 /******************************************************************************
  * xend.c
  * 
- * The grand Xen daemon. For now it's just a console concentrator.
+ * The grand Xen daemon. For now it's just a virtual-console concentrator.
  * 
  * Copyright (c) 2004, K A Fraser
  */
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <xc.h>
+
+/* NB. The following should be kept in sync with the kernel's evtchn driver. */
+#define EVTCHN_DEV_NAME  "/dev/xen/evtchn"
+#define EVTCHN_DEV_MAJOR 10
+#define EVTCHN_DEV_MINOR 200
+#define PORT_NORMAL     0x0000   /* A standard event notification.      */ 
+#define PORT_DISCONNECT 0x8000   /* A port-disconnect notification.     */
+#define PORTIDX_MASK    0x7fff   /* Strip subtype to obtain port index. */
+#define EVTCHN_RESET _IO('E', 1) /* Clear notification buffer. Clear errors. */
+
+/* Error macros. */
+#define ERROR(_f, _a...)     \
+    fprintf ( stderr, "ERROR: " _f "\n" , ## _a );
+#define SYS_ERROR(_f, _a...) \
+    fprintf ( stderr, "ERROR: " _f " [errno=%d (%s)]\n" , \
+              ## _a , errno , strerror(errno) );
+#define HINT(_f, _a...)      \
+    fprintf ( stderr, "Hint: " _f "\n" , ## _a );
+#define ROOT_HINT() HINT("You must execute this daemon as root.")
+#define DOM0_HINT() HINT("You must execute this daemon " \
+                         "on a privileged Xenolinux instance (e.g., DOM0).")
+
+/* The following is to be shared with guest kernels. */
+typedef struct {
+    u8 cmd_type;     /* echoed in response */
+    u8 cmd_subtype;  /* echoed in response */
+    u8 id;           /* echoed in response */
+    u8 length;       /* number of bytes in 'msg' */
+    unsigned char msg[60]; /* command-specific message data */
+} control_msg_t;
+#define CONTROL_RING_SIZE 8
+typedef unsigned int CONTROL_RING_IDX;
+#define MASK_CONTROL_IDX(_i) ((_i)&(CONTROL_RING_SIZE-1))
+typedef struct {
+    control_msg_t tx_ring[CONTROL_RING_SIZE]; /* guest -> DOM0 */
+    control_msg_t rx_ring[CONTROL_RING_SIZE]; /* DOM0 -> guest */
+    CONTROL_RING_IDX tx_req_prod, tx_resp_prod;
+    CONTROL_RING_IDX rx_req_prod, rx_resp_prod;
+} control_comms_t;
+#define CMD_CONSOLE      0
+#define CMD_CONSOLE_DATA 0
+
+#define PAGE_SHIFT 12
+#define PAGE_SIZE  (1<<PAGE_SHIFT)
+
+typedef struct {
+    u64              dom;
+    control_comms_t *comms;
+    CONTROL_RING_IDX tx_req_cons, tx_resp_prod;
+    CONTROL_RING_IDX rx_req_cons, rx_resp_prod;
+} portinfo_t;
+
+static portinfo_t portinfo[1024];    
+
+static control_comms_t *map_comms(int fd, unsigned long pfn)
+{
+    char *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE,
+                       MAP_SHARED, fd, pfn << PAGE_SHIFT);
+    if ( vaddr == MAP_FAILED )
+        return NULL;
+    return (control_comms_t *)(vaddr + 2048);
+}
+
+static void unmap_comms(int fd, control_comms_t *c)
+{
+    char *vaddr = (char *)c - 2048;
+    (void)munmap(vaddr, PAGE_SIZE);
+}
+
+#define PORT_CHUNK 4
 int main(int argc, char **argv)
 {
+    int fd, memfd, xch, chunk;
+    unsigned int bytes, i, port, portid, status;
+    u64 domid;
+    u16 buf[PORT_CHUNK];
+
+    if ( (fd = open(EVTCHN_DEV_NAME, O_RDWR)) == -1 )
+    {
+        SYS_ERROR("Could not open '%s'", EVTCHN_DEV_NAME);
+        ROOT_HINT();
+        HINT("On a non-devfs system you must run 'mknod %s c %d %d'.",
+             EVTCHN_DEV_NAME, EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR);
+        exit(1);
+    }
+
+    if ( (memfd = open("/dev/mem", O_RDWR)) == -1 )
+    {
+        SYS_ERROR("Could not open '/dev/mem'");
+        ROOT_HINT();
+        exit(1);
+    }
+
+    if ( (xch = xc_interface_open()) == -1 )
+    {
+        SYS_ERROR("Could not open Xen control interface");
+        ROOT_HINT();
+        DOM0_HINT();
+        exit(1);
+    }
+
+    while ( (bytes = read(fd, buf, sizeof(buf))) == -1 )
+    {
+        if ( errno == EINTR )
+            continue;
+        SYS_ERROR("Unexpected error reading '%s'.", EVTCHN_DEV_NAME);
+        exit(1);
+    }
+
+    if ( (bytes == 0) || ((bytes & 1) != 0) )
+    {
+        ERROR("Short or bad read length (%d bytes) from '%s'.",
+              bytes, EVTCHN_DEV_NAME);
+        exit(1);
+    }
+
+    chunk = bytes / 2;
+    for ( i = 0; i < chunk; i++ )
+    {
+        port = buf[i] & PORTIDX_MASK;
+        if ( buf[i] & PORT_DISCONNECT )
+        {
+            if ( portinfo[port].comms == NULL )
+                continue;
+            unmap_comms(memfd, portinfo[port].comms);
+            portinfo[port].comms = NULL;
+            (void)write(fd, &buf[i], sizeof(u16));
+            (void)xc_evtchn_close(xch, DOMID_SELF, port);
+        }
+        else
+        {
+            if ( portinfo[port].comms == NULL )
+            {
+                xc_dominfo_t info;
+                xc_evtchn_status(xch, DOMID_SELF, port, 
+                                 &domid, &portid, &status);
+
+                if ( (status == EVTCHNSTAT_closed) ||
+                     ((status == EVTCHNSTAT_disconnected) && (portid == 0)) )
+                {
+                    /* Cleanup sanity: we'll be the grim reaper. */
+                    (void)write(fd, &buf[i], sizeof(u16)); /* PORT_NORMAL */
+                    buf[i] |= PORT_DISCONNECT;
+                    (void)write(fd, &buf[i], sizeof(u16)); /* PORT_DISCON */
+                    continue;
+                }
+
+                /* We only deal with initial ports (id == 0). */
+                if ( portid != 0 )
+                    continue;
+
+                xc_domain_getinfo(xch, domid, 1, &info);
+                portinfo[port].comms = 
+                    map_comms(memfd, info.shared_info_frame);
+                portinfo[port].dom = domid;
+                portinfo[port].tx_req_cons  = 0;
+                portinfo[port].tx_resp_prod = 0;
+                portinfo[port].rx_req_cons  = 0;
+                portinfo[port].rx_resp_prod = 0;
+            }
+
+            do {
+                xc_evtchn_send(xch, port);
+                write(fd, &buf[i], sizeof(u16));
+            } while ( 0 );
+        }
+    }
+
+    (void)xc_interface_close(xch);
+    (void)close(memfd);
+    (void)close(fd);
+
     return 0;
 }
index 919e9855cc988c2e5561ac973860281c30b3ee59..a6449d6d7ea0cc7fea455e89a615e1bd64d56c27 100644 (file)
@@ -138,6 +138,10 @@ static long event_channel_open(evtchn_open_t *open)
     p2->event_channel[port2].remote_port = (u16)port1;
     p2->event_channel[port2].state       = ECS_CONNECTED;
 
+    /* Ensure that the disconnect signal is not asserted. */
+    clear_bit(port1, &p1->shared_info->event_channel_disc[0]);
+    clear_bit(port2, &p2->shared_info->event_channel_disc[0]);
+
     cpu_mask  = set_event_pending(p1, port1);
     cpu_mask |= set_event_pending(p2, port2);
     guest_event_notify(cpu_mask);